﻿namespace ImageProcessing
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Linq;
    using System.Windows.Forms;
    using System.Text;
    using System.Threading;
    using System.Drawing.Drawing2D;

    /// <summary>
    /// ImageEvents for events ob picturebox
    /// </summary>
    public static class ImageEvents
    {
        private static int x, y;
        private static Rectangle cropRect;
        public static Point topLeft, downRight;
        public static double factorZoom = 1;
        public static bool drawing = false;

        /// <summary>
        /// Handles the MouseMove event of the Image control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param>
        public static void Image_MouseMove(object sender, MouseEventArgs e)
        {
            Main.ImageList[Main.CurrImage].MyShaps.MouseMoveAction(sender, e); // for dawing shaps

            if (Main.EMode == EditingMode.Hand)
            {
                if (GlobalVariables.HandcanMove == true)
                {
                    MoveControl(Main.ImagePanel.Controls[0], Main.ImagePanel.Size, e);
                }
            }

            if (Main.EMode == EditingMode.Cropping)
            {
                if (GlobalVariables.HandcanMove == true)
                {
                    UpdateRectangle(e);
                    ((PictureBox)sender).Invalidate();
                }
            }
            //if (Main.EMode == EditingMode.Resizing)
            //{
            //    if (GlobalVariables.HandcanMove == true)
            //    {
            //        ((PictureBox)sender).Image = ImageEvents.PictureBoxZoom(((PictureBox)sender).Image, new Size((e.X - x), (e.Y - y)));
            //    }
            //}
        }

        /// <summary>
        /// Handles the MouseDown event of the Image control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param>
        public static void Image_MouseDown(object sender, MouseEventArgs e)
        {
            Main.ImageList[Main.CurrImage].MyShaps.MouseDownAction(sender, e); // // for dawing shaps

            GlobalVariables.HandcanMove = true;
            if (Main.EMode == EditingMode.Cropping)
            {
                Main.ImageList[Main.CurrImage].RetriveImageArray();
                cropRect = new Rectangle(e.X, e.Y, 0, 0);
            }

            drawing = true;

            ((PictureBox)sender).Invalidate();
            x = e.X;
            y = e.Y;
        }

        /// <summary>
        /// Handles the MouseUp event of the Image control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param>
        public static void Image_MouseUp(object sender, MouseEventArgs e)
        {
            Main.ImageList[Main.CurrImage].MyShaps.MouseUpAction(sender, e); // for dawing shaps
            GlobalVariables.HandcanMove = false;
            if (Main.EMode == EditingMode.Cropping)
            {
                FadeCropping();
            }

            drawing = false;
            ((PictureBox)sender).Invalidate();
        }

        /// <summary>
        /// Handles the MouseWheel event of the Image control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param>
        public static void Image_MouseWheel(object sender, MouseEventArgs e)
        {
            if (Main.EMode == EditingMode.Resizing)
            {
                ((PictureBox)sender).Image = ImageEvents.PictureBoxZoom(((PictureBox)sender).Image, new Size(e.Delta, e.Delta));
            }
        }

        /// <summary>
        /// Pictures the box zoom.
        /// </summary>
        /// <param name="img">The img.</param>
        /// <param name="size">The size.</param>
        /// <returns>zooming image</returns>
        public static Image PictureBoxZoom(Image img, Size size)
        {
            Bitmap bm = new Bitmap(img, Convert.ToInt32(img.Width * size.Width), Convert.ToInt32(img.Height * size.Height));
            Graphics grap = Graphics.FromImage(bm);
            grap.InterpolationMode = InterpolationMode.HighQualityBicubic;
            return bm;
        }

        /// <summary>
        /// Pictures the box zoom WH.
        /// </summary>
        /// <param name="img">The img.</param>
        /// <param name="width">The width.</param>
        /// <param name="height">The height.</param>
        /// <returns>zooming image</returns>
        public static Image PictureBoxZoomWH(Image img)
        {
            Bitmap bm = new Bitmap(img, Convert.ToInt32(img.Width * factorZoom), Convert.ToInt32(img.Height * factorZoom));
            Graphics grap = Graphics.FromImage(bm);
            grap.InterpolationMode = InterpolationMode.HighQualityBicubic;
            return bm;
        }

        public static Image ZoomIn(Image img, int originalw, int originalH)
        {
            factorZoom = 1.1;

            if (img.Width < originalw * 7 && img.Height < originalH * 7)
                return PictureBoxZoomWH(img);
            else
            {
                //    factorZoom = 6;
                return img;
            }
        }

        public static Image ZoomOut(Image img, int originalw, int originalH)
        {
            factorZoom = 0.9;

            if (img.Width > originalw * 0.7 && img.Height > originalH * 0.7)
                return PictureBoxZoomWH(img);
            else
            {
                //    factorZoom = 6;
                return img;
            }
        }

        /// <summary>
        /// Handles the MouseClick event of the Image control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param>
        public static void Image_MouseClick(object sender, MouseEventArgs e)
        {
            //if (Main.EMode == EditingMode.Resizing && Main.ModifierKeys == Keys.Alt)
            //{
            //    if (factorZoom > 1)
            //    {
            //        factorZoom--;
            //        if(factorZoom!=0)
            //        ((PictureBox)sender).Image = ImageEvents.PictureBoxZoom(Operations.DisplayMatrix(Main.ImageList[Main.CurrImage].TempStructArray1), new Size(factorZoom, factorZoom));
            //    }
            //}
            //else if (Main.EMode == EditingMode.Resizing)
            //{
            //    if (factorZoom < 5)
            //    {
            //        factorZoom++;
            //        if (factorZoom != 0)
            //        ((PictureBox)sender).Image = ImageEvents.PictureBoxZoom(Operations.DisplayMatrix(Main.ImageList[Main.CurrImage].TempStructArray1), new Size(factorZoom, factorZoom));
            //    }

            //}

            Main.ImageList[Main.CurrImage].MyShaps.MouseClickAction(sender, e);
            ((PictureBox)sender).Invalidate();
        }

        /// <summary>
        /// Handles the MouseClick event of the Image control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param>
        public static void Image_MouseEnter(object sender, EventArgs e)
        {
            HandleMainCursor();
        }

        /// <summary>
        /// Handles the MouseClick event of the Image control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param>
        public static void Image_MouseLeave(object sender, EventArgs e)
        {
            Main.Instance.Cursor = System.Windows.Forms.Cursors.Default;
        }

        /// <summary>
        /// Updates the rectangle.
        /// </summary>
        /// <param name="e">The <see cref="System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param>
        private static void UpdateRectangle(MouseEventArgs e)
        {
            cropRect = new Rectangle(cropRect.Left, cropRect.Top, e.X - cropRect.Left, e.Y - cropRect.Top);
            topLeft.X = cropRect.Left;
            topLeft.Y = cropRect.Top;
            downRight.X = e.X;
            downRight.Y = e.Y;
        }

        /// <summary>
        /// Fades the cropping.
        /// </summary>
        private static void FadeCropping()
        {
            cropRect.Size = new Size(new Point(0, 0));
            Thread t = null;
            int rowsPerThread = Main.ImageList[Main.CurrImage].Height / Environment.ProcessorCount;
            Semaphore s = new Semaphore(1, 1000);
            int minHeight = 0, maxHeight = 0;
            for (int i = 1; i < Environment.ProcessorCount; i++)
            {
                s.WaitOne();
                minHeight = i * rowsPerThread;
                maxHeight = (i + 1) * rowsPerThread;
                if (i == (Environment.ProcessorCount - 1))
                {
                    t = new Thread(delegate() { CroppingImageSizeThreading(s, minHeight, Main.ImageList[Main.CurrImage].Height, Main.ImageList[Main.CurrImage].ImageStructArray); });
                    t.Start();
                    break;
                }

                t = new Thread(delegate() { CroppingImageSizeThreading(s, minHeight, maxHeight, Main.ImageList[Main.CurrImage].ImageStructArray); });
                t.Start();
            }

            CroppingImageSizeThreading(s, 0, rowsPerThread, Main.ImageList[Main.CurrImage].ImageStructArray);
            Main.ImageList[Main.CurrImage].UpdateImage();
        }

        /// <summary>
        /// Croppings the image size threading.
        /// </summary>
        /// <param name="s">The s.</param>
        /// <param name="minHeight">Height of the min.</param>
        /// <param name="maxHeight">Height of the max.</param>
        /// <param name="image">The image.</param>
        private static void CroppingImageSizeThreading(Semaphore s, int minHeight, int maxHeight, ImageStructure[,] image)
        {
            s.Release();
            for (int i = minHeight; i < maxHeight; i++)
            {
                for (int j = 0; j < Main.ImageList[Main.CurrImage].Width; j++)
                {
                    if (j >= topLeft.X && j <= downRight.X && i >= topLeft.Y && i <= downRight.Y)
                    {
                        continue;
                    }

                    image[i, j].G = 0;
                    image[i, j].R = 0;
                }
            }
        }

        /// <summary>
        /// Handles the MouseDoubleClick event of the Image control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param>
        public static void Image_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            Main.ImageList[Main.CurrImage].MyShaps.MouseDoubleClickAction(sender, e);
            ((PictureBox)sender).Invalidate();
        }

        /// <summary>
        /// Handles the KeyPress event of the Image control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.KeyPressEventArgs"/> instance containing the event data.</param>
        public static void Image_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == 'D' || e.KeyChar == 'd')
            {
                Main.ImageList[Main.CurrImage].MyShaps.AllShapes.Remove(Main.ImageList[Main.CurrImage].MyShaps.SelectedShape);
            }
        }

        /// <summary>
        /// Handles the Paint event of the Image control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.PaintEventArgs"/> instance containing the event data.</param>
        public static void Image_Paint(object sender, PaintEventArgs e)
        {

            if (Main.EMode == EditingMode.Cropping)
            {
                using (Pen pen = new Pen(Color.Red, 2))
                {
                    e.Graphics.DrawRectangle(pen, cropRect);
                }
            }

            // here redrawing ...for drawing shapes            
            for (int i = 0; i < Main.ImageList[Main.CurrImage].MyShaps.AllShapes.Count; i++)
            {
                // use the graphics object in "e" to draw
                Main.ImageList[Main.CurrImage].MyShaps.AllShapes[i].Draw(e.Graphics);
            }

            if (Main.ImageList[Main.CurrImage].MyShaps.TmpShape != null)
            {
                Main.ImageList[Main.CurrImage].MyShaps.TmpShape.DrawForCreation(e.Graphics);
            }

            if (drawing)
            {
                ((PictureBox)sender).Invalidate();
            }
        }

        /// <summary>
        /// Moves the control.
        /// </summary>
        /// <param name="ctrl">The CTRL.</param>
        /// <param name="containerSize">Size of the container.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param>
        private static void MoveControl(Control ctrl, Size containerSize, MouseEventArgs e)
        {
            // if (ContainerSize == null)
            // {
            //  ctrl.Location = new Point((int)ctrl.Location.X + (int)(e.X - x), (int)ctrl.Location.Y + (int)(e.Y - y));
            // }
            // else
            // {
            // if ((ctrl.Location.X <= 0 && (e.X - x) < 0) || (ctrl.Location.Y <= 0 && (e.Y - y) < 0) || (ctrl.Location.X + ctrl.Width >= ContainerSize.Width && (e.X - x) > 0) || (ctrl.Location.Y + ctrl.Height >= ContainerSize.Height && (e.Y - y) > 0))
            // {
            //      return;
            // }
            if (ctrl.Location.X >= 0 && (e.X - x) > 0 && ctrl.Width >= containerSize.Width)
            {
                return;
            }

            if (ctrl.Location.X + ctrl.Width <= containerSize.Width && (e.X - x) < 0 && ctrl.Width >= containerSize.Width)
            {
                return;
            }

            if (ctrl.Location.Y >= 0 && (e.Y - y) > 0 && ctrl.Height >= containerSize.Height)
            {
                return;
            }

            if (ctrl.Location.Y + ctrl.Height <= containerSize.Height && (e.Y - y) < 0 && ctrl.Height >= containerSize.Height)
            {
                return;
            }

            if (ctrl.Location.X <= 0 && (e.X - x) < 0 && ctrl.Width < containerSize.Width)
            {
                return;
            }

            if (ctrl.Location.X + ctrl.Width >= containerSize.Width && (e.X - x) > 0 && ctrl.Width < containerSize.Width)
            {
                return;
            }

            if (ctrl.Location.Y <= 0 && (e.Y - y) < 0 && ctrl.Height < containerSize.Height)
            {
                return;
            }

            if (ctrl.Location.Y + ctrl.Height >= containerSize.Height && (e.Y - y) > 0 && ctrl.Height < containerSize.Height)
            {
                return;
            }

            ctrl.Location = new Point((int)ctrl.Location.X + (int)(e.X - x), (int)ctrl.Location.Y + (int)(e.Y - y));


            //if (((((ctrl.Location.X >= 0 && (e.X - x) > 0) || (ctrl.Location.X + ctrl.Width <= containerSize.Width && (e.X - x) < 0)) && ctrl.Width > containerSize.Width) ||
            //   (((ctrl.Location.Y >= 0 && (e.Y - y) > 0) || (ctrl.Location.Y + ctrl.Height <= containerSize.Height && (e.Y - y) < 0)) && ctrl.Height > containerSize.Height)))
            //{
            //   // x = e.X;
            //   // y = e.Y;
            //    return;
            //}
            // else if ((ctrl.Location.X <= 0 && (e.X - x) < 0) ||
            //  (ctrl.Location.Y <= 0 && (e.Y - y) < 0) ||
            //  (ctrl.Location.X + ctrl.Width >= ContainerSize.Width && (e.X - x) > 0) || 
            //  (ctrl.Location.Y + ctrl.Height >= ContainerSize.Height && (e.Y - y) > 0))
            // {
            //    return;
            // }
            //  else
            //  {
            //ctrl.Location = new Point((int)ctrl.Location.X + (int)(e.X - x), (int)ctrl.Location.Y + (int)(e.Y - y));
            //  }
            //ctrl.Location = new Point((int)ctrl.Location.X + (int)(e.X - x), (int)ctrl.Location.Y + (int)(e.Y - y));


            // if (ctrl.Location.Y < 0)
            // {
            //     ctrl.Location = new Point(ctrl.Location.X, 0);
            // }
            // if (ctrl.Location.X + ctrl.Width > ContainerSize.Width)
            // {
            //    ctrl.Location = new Point(ContainerSize.Width - ctrl.Width, ctrl.Location.Y);
            // }
            // if (ctrl.Location.Y + ctrl.Height > ContainerSize.Height)
            // {
            //    ctrl.Location = new Point(ctrl.Location.X, ContainerSize.Height - ctrl.Height);

            // }
            //  }
        }

        private static void HandleMainCursor()
        {
            switch (Main.EMode)
            {
                case EditingMode.Cropping:
                    Main.Instance.Cursor = Cursors.Cross;
                    break;
                case EditingMode.Hand:
                    Main.Instance.Cursor = Cursors.SizeAll;
                    break;
                case EditingMode.Nothing:
                    Main.Instance.Cursor = Cursors.Default;
                    break;
            }
        }
    }
}
